package com.funcourse.demo.api.restful;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.funcourse.demo.api.restful.io.request.SubmitAnswerRequest;
import com.funcourse.demo.api.restful.io.request.UpdatePersonWechatRequest;
import com.funcourse.demo.api.restful.io.response.ApiResponse;
import com.funcourse.demo.api.restful.io.response.AttendedRoom;
import com.funcourse.demo.api.restful.io.response.busi.CompeteRoomHttpVO;
import com.funcourse.demo.api.restful.io.response.busi.MeVO;
import com.funcourse.demo.api.restful.io.response.error.CommonUsedError;
import com.funcourse.demo.api.restful.io.response.busi.UserVO;
import com.funcourse.demo.api.restful.security.AuthUserHolder;
import com.funcourse.demo.business.CompeteRoomService;
import com.funcourse.demo.business.RoomCacher;
import com.funcourse.demo.model.AttenderStatics;
import com.funcourse.demo.model.CompeteRoom;
import com.funcourse.demo.model.User;
import com.funcourse.demo.model.UserWithScore.Score;
import com.funcourse.demo.model.repo.AttenderStaticsRepo;
import com.funcourse.demo.model.repo.CompeteRoomRepo;
import com.funcourse.demo.model.repo.UserRepo;
import com.funcourse.demo.model.repo.room.AttenderRoomRelationRepo;
import com.funcourse.demo.model.room.AttenderRoomRelation;
import com.funcourse.demo.util.AESUtil;
import com.funcourse.demo.wechat.client.welet.io.WeletUserInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Base64.Decoder;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@CrossOrigin(origins = "*")
@Api(description = "学生答题API")
@RestController
@RequestMapping(path = "#{'/api/'+'${service.version}'+'/attend'}")
public class AttendController {

  @Autowired
  AuthUserHolder authUserHolder;

  @Autowired
  ObjectMapper objectMapper;

  @Autowired
  UserRepo userRepo;

  @Autowired
  CompeteRoomRepo competeRoomRepo;

  @Autowired
  CompeteRoomService competeRoomService;

  @Autowired
  AttenderRoomRelationRepo attenderRoomRelationRepo;

  @Autowired
  AttenderStaticsRepo attenderStaticsRepo;

  @Autowired
  RoomCacher roomCacher;

  /**
   * update welet userinfo
   */
  @ApiOperation(value = "更新微信小程序用户信息")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "Authorization", value = "Authorization", paramType = "header", required = true)
  })
  @PostMapping("/updateMyWeletInfo")
  public ApiResponse<MeVO> updateMyWeletInfo(@RequestBody UpdatePersonWechatRequest request) {
    User authUser = authUserHolder.getAuthUser();
    Decoder decoder = Base64.getDecoder();
    String decrypt = AESUtil
        .decrypt(decoder.decode(request.getEncryptedData()), decoder.decode(authUser.getSessionKey()),
            decoder.decode(request.getIv()));
    WeletUserInfo weletUserInfo;
    try {
      weletUserInfo = objectMapper.readValue(decrypt, WeletUserInfo.class);
    } catch (JsonProcessingException e) {
      log.error("convert decrypt msg to userinfo failed {}",decrypt,e);
      return new ApiResponse(CommonUsedError.BAD_REQUEST, null);
    }
    log.debug("welet user info decryped {}",weletUserInfo.getUnionId());
    User byUnionId = userRepo.findByUnionId(weletUserInfo.getUnionId());
    log.debug("byUnionId found {} with auth id {}",byUnionId == null?null:byUnionId.getId(),authUser.getId());
    if(null != byUnionId){
      final Set<String> weletOpenIds = byUnionId.getWeletOpenIds();
      weletOpenIds.add(weletUserInfo.getOpenId());
      if(!byUnionId.getId().equals(authUser.getId())){
        userRepo.deleteById(authUser.getId());
      }
    }else{//null == byUnionId
      byUnionId = authUser;
      byUnionId.setUnionId(weletUserInfo.getUnionId());
    }
    byUnionId.setNickName(weletUserInfo.getNickName());
    byUnionId.setAvatarUrl(weletUserInfo.getAvatarUrl());
    byUnionId.setSessionKey(authUser.getSessionKey());
    userRepo.save(byUnionId);
    return ApiResponse.ok(new MeVO(byUnionId));
  }

  /**
   * join a room room id check if room available ;add me in room members; publish room members to
   * all members ok/fail
   */
  @ApiOperation(value = "加入房间")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "Authorization", value = "Authorization", paramType = "header", required = true)
  })
  @PostMapping("/joinRoom")
  public ApiResponse<CompeteRoom> joinRoom(String roomId) {
    return competeRoomService.joinRoom(roomId);
  }

  @ApiOperation(value = "用房间号加入房间")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "Authorization", value = "Authorization", paramType = "header", required = true)
  })
  @PostMapping("/joinRoomByNo")
  public ApiResponse<CompeteRoom> viewRoomInfoByNo(String roomNo) {
    return competeRoomService.viewRoomInfoByNo(roomNo);
  }

  /**
   * join a room room id check if room available ;add me in room members; publish room members to
   * all members ok/fail
   */
  @ApiOperation(value = "离开房间")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "Authorization", value = "Authorization", paramType = "header", required = true)
  })
  @PostMapping("/leaveRoom")
  public ApiResponse leaveRoom(String roomId) {
    return competeRoomService.leaveRoom(roomId);
  }

  /**receive roommate entrance notice
   * room id / current room members
   */

  /**receive room start compete notice
   * room id / start
   */

  /**receive room compete rank change notice
   * room id / current room members
   */


  /**
   * submit my answer my score/ room id change my score in room members; re-rank room members;
   * publish room members to all members in the room ok/fail
   */
  @ApiOperation(value = "提交答案")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "Authorization", value = "Authorization", paramType = "header", required = true)
  })
  @PostMapping("/submitMyAnswer")
  public ApiResponse submitMyAnswer(@RequestBody  SubmitAnswerRequest request) {
    return competeRoomService.submitMyAnswer(request.getRoomId(),new Score(request.getQuestionNumber(),request.getScore(),request.getChoiceNumber(),request.getMultiChoiceNumbers(),request.getAnswers()));
  }

  /**view recent rooms
   *
   * recent rooms
   */
  @ApiOperation(value = "查看参加过的房间列表")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "Authorization", value = "Authorization", paramType = "header", required = true)
  })
  @PostMapping("/viewAttendedRooms")
  public ApiResponse<List<AttendedRoom>> viewAttendedRooms(int page, int size) {
    User authUser = authUserHolder.getAuthUser();
    Page<AttenderRoomRelation> attendRooms = attenderRoomRelationRepo
        .findByAttenderId(authUser.getId(),
            PageRequest.of(page, size, Sort.by(Direction.DESC, "attendTime")));
    List<AttenderRoomRelation> attenderRoomRelations = attendRooms.getContent();
    if (CollectionUtils.isEmpty(attenderRoomRelations)) {
      return ApiResponse.ok(new ArrayList<>(0));
    }
    Iterable<CompeteRoom> competeRooms = competeRoomRepo
        .findAllById(attenderRoomRelations.stream().map(AttenderRoomRelation::getRoomId).collect(
            Collectors.toList()));
    return ApiResponse.ok(AttendedRoom.buildAttendedRooms(attenderRoomRelations,competeRooms));
  }

  @ApiOperation(value = "查看战绩")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "Authorization", value = "Authorization", paramType = "header", required = true)
  })
  @PostMapping("/viewReport")
  public ApiResponse<AttenderStatics> viewReport() {
    User authUser = authUserHolder.getAuthUser();
    AttenderStatics byUserId = attenderStaticsRepo.findByUserId(authUser.getId());
    if(null == byUserId){
      byUserId = new AttenderStatics(null,null,0,0,0,0);
    }
    return ApiResponse.ok(byUserId);
  }

  /**view room compete rank
   * room id
   * room info
   */
  @ApiOperation(value = "查看我参加过的房间")
  @PostMapping("/viewRoomInfo")
  public ApiResponse<CompeteRoomHttpVO> viewRoomInfo(String roomId,String userId) {
    CompeteRoom competeRoom = roomCacher.getRoomById(roomId);
    if (null != competeRoom) {
      return new ApiResponse(CommonUsedError.SUCCESS, new CompeteRoomHttpVO(competeRoom,userId,5,true));
    }
    return new ApiResponse(CommonUsedError.BAD_REQUEST.customizedError("no room found"), null);
  }

}
